// Copyright (c) 2023 - 2025 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package function provides functional programming utilities for function composition,
// transformation, and manipulation.
//
// This package offers a comprehensive set of tools for working with functions in a
// functional programming style, including:
//
//   - Function composition (Pipe, Flow)
//   - Currying and uncurrying
//   - Partial application (Bind)
//   - Function transformation (Flip, Swap)
//   - Utility functions (Identity, Constant, etc.)
//
// # Core Concepts
//
// Function Composition:
//
// Pipe and Flow are the primary composition primitives. They differ in the order
// of function application:
//
//   - Pipe: Applies functions left-to-right (data flows through the pipeline)
//   - Flow: Applies functions right-to-left (mathematical function composition)
//
// Example:
//
//	// Pipe: f(g(h(x)))
//	result := Pipe3(x, h, g, f)
//
//	// Flow: f(g(h(x)))
//	composed := Flow3(f, g, h)
//	result := composed(x)
//
// Currying:
//
// Currying transforms a function with multiple parameters into a sequence of
// functions each taking a single parameter.
//
// Example:
//
//	add := func(a, b int) int { return a + b }
//	curriedAdd := Curry2(add)
//	add5 := curriedAdd(5)
//	result := add5(3)  // 8
//
// Partial Application:
//
// Bind functions allow you to fix some arguments of a function, creating a new
// function with fewer parameters.
//
// Example:
//
//	multiply := func(a, b int) int { return a * b }
//	double := Bind1st(multiply, 2)
//	result := double(5)  // 10
//
// # Common Functions
//
// Identity and Constants:
//
//	Identity[A any](a A) A                    // Returns its argument unchanged
//	Constant[A any](a A) func() A             // Creates a nullary constant function
//	Constant1[B, A any](a A) func(B) A        // Creates a unary constant function
//	Constant2[B, C, A any](a A) func(B, C) A  // Creates a binary constant function
//
// Function Transformation:
//
//	Flip[T1, T2, R any](func(T1) func(T2) R) func(T2) func(T1) R  // Reverses curried function parameters
//	Swap[T1, T2, R any](func(T1, T2) R) func(T2, T1) R            // Swaps binary function parameters
//
// Pointer Utilities:
//
//	Ref[A any](a A) *A      // Creates a pointer to a value
//	Deref[A any](a *A) A    // Dereferences a pointer
//	IsNil[A any](a *A) bool // Checks if pointer is nil
//
// Selection:
//
//	First[T1, T2 any](t1 T1, t2 T2) T1   // Returns first argument
//	Second[T1, T2 any](t1 T1, t2 T2) T2  // Returns second argument
//
// Conditional:
//
//	Ternary[A, B any](pred func(A) bool, onTrue func(A) B, onFalse func(A) B) func(A) B
//	Switch[K comparable, T, R any](kf func(T) K, cases map[K]func(T) R, default func(T) R) func(T) R
//
// # Generated Functions
//
// This package includes generated functions for various arities (0-20 parameters):
//
//   - PipeN: Left-to-right composition
//   - FlowN: Right-to-left composition
//   - CurryN: Currying for N-ary functions
//   - UncurryN: Uncurrying for N-ary functions
//   - BindXofN: Partial application binding specific parameters
//   - IgnoreXofN: Partial application ignoring specific parameters
//
// # Usage Examples
//
// Basic composition:
//
//	// Transform a string: trim, lowercase, add prefix
//	process := Flow3(
//	    func(s string) string { return "processed: " + s },
//	    strings.ToLower,
//	    strings.TrimSpace,
//	)
//	result := process("  HELLO  ")  // "processed: hello"
//
// Currying and partial application:
//
//	// Create specialized functions from general ones
//	divide := func(a, b float64) float64 { return a / b }
//	divideBy2 := Bind2nd(divide, 2.0)
//	half := divideBy2(10.0)  // 5.0
//
// Working with predicates:
//
//	isPositive := func(n int) bool { return n > 0 }
//	isEven := func(n int) bool { return n%2 == 0 }
//
//	classify := Ternary(
//	    isPositive,
//	    Constant1[int]("positive"),
//	    Constant1[int]("non-positive"),
//	)
//	result := classify(5)   // "positive"
//	result2 := classify(-3) // "non-positive"
//
// Memoization:
//
//	expensive := func(n int) int {
//	    time.Sleep(time.Second)
//	    return n * n
//	}
//	memoized := Memoize(expensive)
//	result1 := memoized(5)  // Takes 1 second
//	result2 := memoized(5)  // Instant (cached)
package function

//go:generate go run .. pipe --count 20 --filename gen.go

//go:generate go run .. bind --count 5 --filename binds.go
